using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.Package;
using System.Runtime.InteropServices;
using NBusiness.VisualStudio.Language;
using Microsoft.VisualStudio.TextManager.Interop;
using Microsoft.VisualStudio;
using NBusiness.CodeDom;
using NBusiness.ESharp;
using NBusiness.ESharp.Compiler;
using System.IO;
using NBusiness.CodeDom.Compiler;

namespace NBusiness.VisualStudio
{
    [Guid(Guids.guidNBusinessLanguageServiceString)]
    public partial class ESharpLanguageService : LanguageService, IVsLanguageTextOps
    {
        private LanguagePreferences _preferences;
        private IScanner _scanner;
        private ESharpLibraryManager _manager;

        private static ESharpColorableItem[] colorableItems = {
            // The first 6 items in this list MUST be these default items.
            new ESharpColorableItem("Keyword", COLORINDEX.CI_BLUE, COLORINDEX.CI_USERTEXT_BK),
            new ESharpColorableItem("Comment", COLORINDEX.CI_DARKGREEN, COLORINDEX.CI_USERTEXT_BK),
            new ESharpColorableItem("Identifier", COLORINDEX.CI_AQUAMARINE, COLORINDEX.CI_USERTEXT_BK),
            new ESharpColorableItem("String", COLORINDEX.CI_MAROON, COLORINDEX.CI_USERTEXT_BK),
            new ESharpColorableItem("Number", COLORINDEX.CI_SYSPLAINTEXT_FG, COLORINDEX.CI_USERTEXT_BK),
            new ESharpColorableItem("Text", COLORINDEX.CI_SYSPLAINTEXT_FG, COLORINDEX.CI_USERTEXT_BK)
        };

        public ESharpLanguageService(ESharpLibraryManager manager)
            : base()
        {
            _manager = manager;
        }

        public override LanguagePreferences GetLanguagePreferences()
        {
            if (_preferences == null)
            {
                _preferences = new LanguagePreferences(
                    this.Site,
                    typeof(ESharpLanguageService).GUID,
                    this.Name);
            }
            return _preferences;
        }

        public override IScanner GetScanner(IVsTextLines buffer)
        {
            if (_scanner == null)
            {
                _scanner = new ESharpScanner(this);
            }
            return _scanner;
        }

        public override string Name
        {
            get { return SR.GetString("ESharpLanguageService"); }
        }

        public override AuthoringScope ParseSource(ParseRequest req)
        {
            if (req == null)
                throw new ArgumentNullException("req");

            return new ESharpScope(this, req);
        }

        #region Custom coloring
        public override int GetItemCount(out int count)
        {
            count = colorableItems.Length;
            return Microsoft.VisualStudio.VSConstants.S_OK;
        }

        public override int GetColorableItem(int index, out IVsColorableItem item)
        {
            if (index < 1)
            {
                throw new ArgumentOutOfRangeException("index");
            }
            item = colorableItems[index - 1];
            return VSConstants.S_OK;
        }
        #endregion

        public override Source CreateSource(IVsTextLines buffer)
        {
            ESharpSource source = new ESharpSource(this, buffer, GetColorizer(buffer));
            return source;
        }

        #region Current root
        ESharpParser _parser = new ESharpParser();
        private Dictionary<string, ESharpSourceFileInfo> _files = new Dictionary<string, ESharpSourceFileInfo>();
        internal EntityRoot GetCurrentRoot()
        {
            //Optimize this so it only rebuilds files that are changed
            ESharpRoot root = new ESharpRoot();
            foreach (string filename in _manager.GetFileNames())
            {
                ESharpSourceFileInfo file = null;
                if (_files.ContainsKey(filename))
                {
                    file = _files[filename];
                }
                else
                {
                    file = new ESharpSourceFileInfo();
                    file.FileName = filename;
                    _files.Add(filename, file);
                }

                Source s = GetSource(filename);
                if (s != null && s.IsDirty)
                {
                    file.Body = s.GetText();
                }
                else if (File.Exists(filename) && file.Body == null)
                {
                    file.Body = File.ReadAllText(filename);
                }

                if (file.Body != null)
                {
                    _parser.BuildRoot(root, file.Body, filename);
                }
            }
            (root as IAttachable).Attach();

            return root;
        } 
        #endregion

        #region IVsTextOps
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")]
        int IVsLanguageTextOps.Format(IVsTextLayer pTextLayer, TextSpan[] ptsSel)
        {
            return VSConstants.E_NOTIMPL;
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")]
        int IVsLanguageTextOps.GetDataTip(IVsTextLayer pTextLayer, TextSpan[] ptsSel, TextSpan[] ptsTip, out string pbstrText)
        {
            pbstrText = string.Empty;
            return VSConstants.E_NOTIMPL;
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")]
        int IVsLanguageTextOps.GetPairExtent(IVsTextLayer pTextLayer, TextAddress ta, TextSpan[] pts)
        {
            return VSConstants.E_NOTIMPL;
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")]
        int IVsLanguageTextOps.GetWordExtent(IVsTextLayer pTextLayer, TextAddress ta, WORDEXTFLAGS flags, TextSpan[] pts)
        {
            return VSConstants.E_NOTIMPL;
        }
        #endregion
    }
}
